/**
 * 
 */
#include "rtthread.h"
#include <rtdevice.h>
#include <drv_gpio.h>
#include <drv_spi.h>
#include "drv_lcd.h"
#include "rtdbg.h"

#define LCD_DC_PIN            GET_PIN(A, 3)     
#define LCD_RES_PIN           GET_PIN(C, 4)     // lcd复位引脚
#define LCD_BLK_PIN           GET_PIN(C, 5)     // lcd背光亮度调节引脚


static struct rt_spi_device *spi_dev_lcd;


static int rt_hw_lcd_config(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    if (RT_EOK != rt_hw_spi_device_attach("spi1", "spi10", GET_PIN(A, 4)))
    {
        LOG_E("Failed to attach the spi device.");
        return -RT_ERROR;
    }

    spi_dev_lcd = (struct rt_spi_device *)rt_device_find("spi10");
    if(spi_dev_lcd == RT_NULL) 
    {
        LOG_E("lcd screen device no find");
        return -RT_ERROR;
    }

    /* config spi */
    {
        struct rt_spi_configuration cfg = {0};
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
        cfg.max_hz = 32 * 1000 * 1000; /* 18M,SPI max 18MHz,lcd 4-wire spi */

        rt_spi_configure(spi_dev_lcd, &cfg);
    }

    return RT_EOK;
}

static rt_err_t lcd_write_cmd(const rt_uint8_t cmd)
{
    rt_size_t len;

    rt_pin_write(LCD_DC_PIN, PIN_LOW);

    len = rt_spi_send(spi_dev_lcd, &cmd, 1);
    rt_pin_write(LCD_DC_PIN, PIN_HIGH);

    if (len != 1)
    {
        LOG_I("lcd_write_cmd error. %d", len);
        return -RT_ERROR;
    }
    else
    {
        return RT_EOK;
    }
    
}

static rt_err_t lcd_write_data(const rt_uint8_t data)
{
    rt_size_t len;

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);

    len = rt_spi_send(spi_dev_lcd, &data, 1);

    if (len != 1)
    {
        LOG_I("lcd_write_data error. %d", len);
        return -RT_ERROR;
    }
    else
    {
        return RT_EOK;
    }
}

// #ifndef APP_USING_LVGL
static rt_err_t lcd_write_half_word(const rt_uint16_t da)
{
    rt_size_t len;
    char data[2] = {0};

    data[0] = da >> 8;
    data[1] = da;

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    len = rt_spi_send(spi_dev_lcd, data, 2);
    if (len != 2)
    {
        LOG_I("lcd_write_half_word error. %d", len);
        return -RT_ERROR;
    }
    else
    {
        return RT_EOK;
    }
}
// #endif /* BSP_USING_LVGL */

static void lcd_gpio_init(void)
{
    rt_pin_mode(LCD_DC_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_RES_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_BLK_PIN, PIN_MODE_OUTPUT);

    rt_pin_write(LCD_BLK_PIN, PIN_LOW);
    rt_pin_write(LCD_RES_PIN, PIN_LOW);
    rt_thread_delay(RT_TICK_PER_SECOND / 10); /* wait at least 100ms for reset */
    rt_pin_write(LCD_RES_PIN, PIN_HIGH);
    rt_thread_delay(RT_TICK_PER_SECOND / 10); /* wait at least 100ms for reset */
}

// static void lcd_display_brightness(rt_uint8_t percent)
// {
    
// }

void lcd_display_on(void)
{
    rt_pin_write(LCD_BLK_PIN, PIN_HIGH);
    // rt_pin_write(LCD_RES_PIN, PIN_HIGH);
    // rt_pin_write(LCD_DC_PIN, PIN_HIGH);
}

void lcd_display_off(void)
{
    rt_pin_write(LCD_BLK_PIN, PIN_LOW);
    // rt_pin_write(LCD_RES_PIN, PIN_LOW);
    // rt_pin_write(LCD_DC_PIN, PIN_LOW);
}

static void lcd_address_set(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
{
	if(USE_HORIZONTAL==0)
	{
		lcd_write_cmd(0x2a);
		lcd_write_half_word(x1+TFT_COLUMN_OFFSET);
		lcd_write_half_word(x2+TFT_COLUMN_OFFSET);
		lcd_write_cmd(0x2b);
		lcd_write_half_word(y1+TFT_LINE_OFFSET);
		lcd_write_half_word(y2+TFT_LINE_OFFSET);
		lcd_write_cmd(0x2c);
	}
	else if(USE_HORIZONTAL==1)
	{
		lcd_write_cmd(0x2a);
		lcd_write_half_word(x1+TFT_COLUMN_OFFSET);
		lcd_write_half_word(x2+TFT_COLUMN_OFFSET);
		lcd_write_cmd(0x2b);
		lcd_write_half_word(y1+TFT_LINE_OFFSET);
		lcd_write_half_word(y2+TFT_LINE_OFFSET);
		lcd_write_cmd(0x2c);
	}
	else if(USE_HORIZONTAL==2)
	{
		lcd_write_cmd(0x2a);
		lcd_write_half_word(x1+TFT_COLUMN_OFFSET);
		lcd_write_half_word(x2+TFT_COLUMN_OFFSET);
		lcd_write_cmd(0x2b);
		lcd_write_half_word(y1+TFT_LINE_OFFSET);
		lcd_write_half_word(y2+TFT_LINE_OFFSET);
		lcd_write_cmd(0x2c);
	}
	else
	{
		lcd_write_cmd(0x2a);
		lcd_write_half_word(x1);
		lcd_write_half_word(x2);
		lcd_write_cmd(0x2b);
		lcd_write_half_word(y1);
		lcd_write_half_word(y2);
		lcd_write_cmd(0x2c);
	}
}

static int rt_hw_lcd_init(void)
{
    rt_hw_lcd_config();
    lcd_gpio_init();

    lcd_write_cmd(0x36); 
    if(USE_HORIZONTAL==0)lcd_write_data(0x00);
    else if(USE_HORIZONTAL==1)lcd_write_data(0x60);
    else if(USE_HORIZONTAL==2)lcd_write_data(0xa0);
    else lcd_write_data(0xc0);

    lcd_write_cmd(0x3A); 
    lcd_write_data(0x05);

    lcd_write_cmd(0xB2);
    lcd_write_data(0x0C);
    lcd_write_data(0x0C);
    lcd_write_data(0x00);
    lcd_write_data(0x33);
    lcd_write_data(0x33);

    lcd_write_cmd(0xB7); 
    lcd_write_data(0x35);  

    lcd_write_cmd(0xBB);
    lcd_write_data(0x19);

    lcd_write_cmd(0xC0);
    lcd_write_data(0x2C);

    lcd_write_cmd(0xC2);
    lcd_write_data(0x01);

    lcd_write_cmd(0xC3);
    lcd_write_data(0x12);   

    lcd_write_cmd(0xC4);
    lcd_write_data(0x20);  

    lcd_write_cmd(0xC6); 
    lcd_write_data(0x0F);    

    lcd_write_cmd(0xD0); 
    lcd_write_data(0xA4);
    lcd_write_data(0xA1);

    lcd_write_cmd(0xE0);
    lcd_write_data(0xD0);
    lcd_write_data(0x04);
    lcd_write_data(0x0D);
    lcd_write_data(0x11);
    lcd_write_data(0x13);
    lcd_write_data(0x2B);
    lcd_write_data(0x3F);
    lcd_write_data(0x54);
    lcd_write_data(0x4C);
    lcd_write_data(0x18);
    lcd_write_data(0x0D);
    lcd_write_data(0x0B);
    lcd_write_data(0x1F);
    lcd_write_data(0x23);

    lcd_write_cmd(0xE1);
    lcd_write_data(0xD0);
    lcd_write_data(0x04);
    lcd_write_data(0x0C);
    lcd_write_data(0x11);
    lcd_write_data(0x13);
    lcd_write_data(0x2C);
    lcd_write_data(0x3F);
    lcd_write_data(0x44);
    lcd_write_data(0x51);
    lcd_write_data(0x2F);
    lcd_write_data(0x1F);
    lcd_write_data(0x1F);
    lcd_write_data(0x20);
    lcd_write_data(0x23);

    lcd_write_cmd(0x21); 

    lcd_write_cmd(0x11); 
    //Delay (120); 

    lcd_write_cmd(0x29); 


    // 设置列地址
    lcd_write_cmd(0x2A); // 列地址设置
    lcd_write_data(0x00); // 起始列地址高位
    lcd_write_data(0x00); // 起始列地址低位
    lcd_write_data(0x00); // 结束列地址高位
    lcd_write_data(0xEF); // 结束列地址低位（240 列）

    // 设置行地址
    lcd_write_cmd(0x2B); // 行地址设置
    lcd_write_data(0x00); // 起始行地址高位
    lcd_write_data(0x00); // 起始行地址低位
    lcd_write_data(0x00); // 结束行地址高位
    lcd_write_data(0xC5); // 结束行地址低位（198 行）

    lcd_write_cmd(0x2C); // 内存写入

    // 初始化完成后打开背光
    lcd_display_on();

}
INIT_DEVICE_EXPORT(rt_hw_lcd_init);


/**
 * full color array on the lcd.
 *
 * @param   x_start     start of x position
 * @param   y_start     start of y position
 * @param   x_end       end of x position
 * @param   y_end       end of y position
 * @param   color       Fill color array's pointer
 *
 * @return  void
 */
void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, void *pcolor)
{
    rt_uint32_t size = 0;

    size = (x_end - x_start + 1) * (y_end - y_start + 1) * 2/*16bit*/;
    lcd_address_set(x_start, y_start, x_end, y_end);
    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    rt_spi_send(spi_dev_lcd, pcolor, size);
}

